package com.zhou.shiro.realm;

import javafx.scene.SubScene;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.credential.Md5CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * Created by Mr-chang on 2016/5/11.
 */

public class MyRealm extends AuthorizingRealm {
    /**
     * 授权方法
     * 1.实际返回的是 SimpleAuthorizationInfo 类的对象
     * 2.可以调用 SimpleAuthorizationInfo 的 addRole 来添加当前登录的 user的权限信息
     * 3.可以从 PrincipalCollection 参数的 getPrimaryPrincipal() 方法来获取用户信息
     *
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        Object pricipal = principalCollection.getPrimaryPrincipal();
        if ("admin".equals(pricipal))
            info.addRole("admin");
        if ("user".equals(pricipal))
            info.addRole("list");

        info.addRole("user");
        return info;
    }

    /**
     * 认证方法
     * 1.编写表单 ：表单的 action 和 username,password的参数都是什么
     * 提交到你想提交的地方，username和password 参数名称任意
     * 2.例如提交到了一个spring mvc的handler：
     * 2.1获取用户名，密码
     * 2.2获取当前用户   Subject currentUser = SecurityUtils.getSubject();
     * 2.3将用户名密码封装成UsernamePasswordToken   UsernamePasswordToken token = new UsernamePasswordToken(username, password);
     * 2.4执行认证操作 currentUser.login(token);
     * 3.当Subject 调用Login方法时，机会触发当前 doGetAuthenticationInfo 方法，且会把UsernamePasswordToken 对象传入
     * 然后在该方法中执行真正的认证:访问数据库进行比对
     * 3.1获取用户名和密码
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println(token.getPrincipal());
        System.out.println(token.getCredentials());

        //1.从 token 中获取登录的 username 注意不需要获取password

        //2.利用 username 查询数据库得到的用户信息

        //3.创建 SimpleAuthenticationInfo 对象并返回，注意该对象的凭证是从数据库中查询得到的。
        //而不是页面输入的，实际的密码校验可以交由shiro来完成

        //4.关于密码加密的事：shiro的密码加密可以非常的复杂，但是实现起来却可以非常简单
        //  4.1可以选择加密方式:在当前的realm中，编写一个 public 类型的不带参数的方法，使用@PostConstruct
        //      注释进行修饰，在其中设置密码的匹配方式
        //  4.2 设置盐值 : 盐值一般是从数据库中查询得到的
        //  4.3 调用 new SimpleAuthenticationInfo(principal, credentials, credentialsSalt,realmName)构造器
        //      返回 SimpleAuthenticationInfo 对象   credentialsSalt 为 Object salt = new Md5Hash(saltSource);


        //登录的主要信息：可以是一个实体类对象，但该实体类的对象一定是根据token的username查询得到的
        Object principal = token.getPrincipal();
        //认证信息: 从数据库中查询出来的信息.密码的比对交给shiro去比较
        //String credentials = "123456";
        String credentials = "daf08e3fa8331247e408bb469372f0e8";


        //设置盐值 : 盐值一般是从数据库中查询得到的
        String source = "abcdef";
        ByteSource credentialsSalt = new Md5Hash(source);

        //当前 Rleam 的 name
        String realmName = getName();

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt,realmName);
        return info;
    }

    //    @PostConstruct ：相当于bean 节点的 init-method 配置
    //@PostConstructs
    private  void setCredentialMatcher(){
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        credentialsMatcher.setHashIterations(1024);
        setCredentialsMatcher(credentialsMatcher);
    }

    public static void main(String args[]){

        String saltSource = "abcdef";

        String hashAlgorithmName = "MD5";
        String credentials = "admin";
        Object salt = new Md5Hash(saltSource);

      //  System.out.println(salt);

        int  hashIterations = 1024;


        Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
        System.out.println(result);
        System.out.println(result.toString().equals("daf08e3fa8331247e408bb469372f0e8"));
    }
}
